Skip to content

Conversation

@BrianLusina
Copy link
Owner

@BrianLusina BrianLusina commented Nov 16, 2025

Describe your change:

Find the longest self contained substring

  • Add an algorithm?
  • Fix a bug or typo in an existing algorithm?
  • Documentation change?

Checklist:

  • I have read CONTRIBUTING.md.
  • This pull request is all my own work -- I have not plagiarized.
  • I know that pull requests will not be merged if they fail the automated tests.
  • This PR only changes one algorithm file. To ease review, please open separate PRs for separate algorithms.
  • All new Python files are placed inside an existing directory.
  • All filenames are in all lowercase characters with no spaces or dashes.
  • All functions and variable names follow Python naming conventions.
  • All function parameters and return values are annotated with Python type hints.
  • All functions have doctests that pass the automated testing.
  • All new algorithms have a URL in its comments that points to Wikipedia or other similar explanation.
  • If this pull request resolves one or more open issues then the commit message contains Fixes: #{$ISSUE_NO}.

Summary by CodeRabbit

  • New Features

    • New algorithm added to find the longest self-contained substring within a given string, optimized with O(n) time complexity.
  • Documentation

    • Added comprehensive documentation detailing the algorithm approach, complexity analysis, and illustrative examples.
    • Updated project directory to include new feature entries.
  • Tests

    • Comprehensive test coverage added, including typical scenarios, edge cases, and boundary conditions.

@BrianLusina BrianLusina self-assigned this Nov 16, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

Warning

Rate limit exceeded

@BrianLusina has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 28 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between a3d3e16 and b80c428.

📒 Files selected for processing (1)
  • pystrings/longest_self_contained_substring/__init__.py (1 hunks)

Walkthrough

This PR introduces a new "Longest Self-Contained Substring" algorithm to the pystrings collection. Changes include a comprehensive README explaining the problem and solution, two implementation functions using character occurrence mapping, a full test suite, and updates to the project directory index.

Changes

Cohort / File(s) Summary
Documentation and Index Updates
DIRECTORY.md, pystrings/length_of_longest_substring/README.md
Added directory entries for the new algorithm problem and tests; reformatted existing README title to Markdown H1 header
New Algorithm Implementation
pystrings/longest_self_contained_substring/README.md, pystrings/longest_self_contained_substring/__init__.py
Added complete problem documentation with algorithm explanation and complexity analysis; implemented two functions (longest_self_contained_substring and max_substring_length) using first/last occurrence tracking to identify self-contained substrings
Test Suite
pystrings/longest_self_contained_substring/test_longest_self_contained_substring.py
Created comprehensive unit tests covering typical cases, edge cases, and negative results for both implementation functions

Sequence Diagram

sequenceDiagram
    participant Caller
    participant longest_self_contained_substring
    participant Helper as Character Mapping

    Caller->>longest_self_contained_substring: Call with string s
    longest_self_contained_substring->>Helper: Precompute first & last<br/>occurrences of each char
    Helper-->>longest_self_contained_substring: Map of char positions
    
    rect rgba(100, 200, 150, 0.3)
    note over longest_self_contained_substring: Iterate all substrings<br/>(excluding full string)
    longest_self_contained_substring->>longest_self_contained_substring: For each substring,<br/>verify no char appears<br/>outside its bounds
    end
    
    alt Valid self-contained found
        longest_self_contained_substring-->>Caller: Return max length
    else No valid substring
        longest_self_contained_substring-->>Caller: Return -1
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Areas requiring attention:

  • Algorithm correctness for identifying self-contained substrings in both implementations
  • Verification that test cases adequately cover edge cases (single characters, all identical characters, empty/minimal strings)
  • Comparison between the two implementation approaches to ensure both are logically sound and produce identical results

Poem

🐰 A substring contained within itself, how neat!
Characters dance in bounded retreat,
No escaping their window, no straying outside—
Two clever solutions with tested pride! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(strings): longest self contained substring' clearly and concisely describes the main change—adding a new algorithm for finding the longest self-contained substring.
Description check ✅ Passed The PR description follows the template structure, clearly describes the change, marks appropriate checklist items, and indicates both algorithm addition and documentation changes.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
pystrings/longest_self_contained_substring/test_longest_self_contained_substring.py (1)

5-71: Consider more descriptive test method names.

While the test coverage is comprehensive and both functions are properly validated, test method names like test_1, test_2, etc. don't convey what scenario is being tested. Consider using descriptive names like test_returns_two_for_xyyx or test_returns_negative_one_when_no_valid_substring to improve test readability and maintainability.

Example refactor for a few tests:

-    def test_1(self):
+    def test_returns_two_for_string_with_mirrored_chars(self):
         s = "xyyx"
         expected = 2
         actual = longest_self_contained_substring(s)
         self.assertEqual(expected, actual)

-    def test_2(self):
+    def test_returns_negative_one_when_no_self_contained_substring(self):
         s = "xyxy"
         expected = -1
         actual = longest_self_contained_substring(s)
         self.assertEqual(expected, actual)

Also applies to: 73-139

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e43536e and a3d3e16.

⛔ Files ignored due to path filters (36)
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_1.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_2.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_3.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_4.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_5.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_6.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_7.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/longest_self_contained_substring_example_8.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_1.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_10.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_11.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_12.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_13.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_14.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_15.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_16.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_17.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_18.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_19.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_2.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_20.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_21.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_22.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_23.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_24.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_25.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_26.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_27.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_28.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_3.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_4.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_5.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_6.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_7.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_8.png is excluded by !**/*.png
  • pystrings/longest_self_contained_substring/images/solution/longest_self_contained_substring_solution_9.png is excluded by !**/*.png
📒 Files selected for processing (5)
  • DIRECTORY.md (1 hunks)
  • pystrings/length_of_longest_substring/README.md (1 hunks)
  • pystrings/longest_self_contained_substring/README.md (1 hunks)
  • pystrings/longest_self_contained_substring/__init__.py (1 hunks)
  • pystrings/longest_self_contained_substring/test_longest_self_contained_substring.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pystrings/longest_self_contained_substring/test_longest_self_contained_substring.py (1)
pystrings/longest_self_contained_substring/__init__.py (2)
  • longest_self_contained_substring (1-52)
  • max_substring_length (55-97)
🪛 LanguageTool
pystrings/longest_self_contained_substring/README.md

[style] ~8-~8: This phrase is redundant. Consider using “outside”.
Context: ...n t does not appear anywhere else in s (outside of t). In other words, all characters in ...

(OUTSIDE_OF)


[style] ~10-~10: Consider using a different adverb to strengthen your wording.
Context: ...In other words, all characters in t are completely unique to that substring within the str...

(COMPLETELY_ENTIRELY)


[style] ~77-~77: Using many exclamation marks might seem excessive (in this case: 32 exclamation marks for a text that’s 6188 characters long)
Context: ...elf_contained_substring_solution_1.png) Solution 2 Solution 3 Solution 4 Solution 5 Solution 6 Solution 7 Solution 8 Solution 9 Solution 10 Solution 11 Solution 12 Solution 13 Solution 14 Solution 15 Solution 16 Solution 17 Solution 18 Solution 19 Solution 20 Solution 21 Solution 22 Solution 23 Solution 24 Solution 25 Solution 26 ![Solution 27](./images/solution/longest_...

(EN_EXCESSIVE_EXCLAMATION)

🪛 markdownlint-cli2 (0.18.1)
DIRECTORY.md

706-706: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)


707-707: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (3)
pystrings/length_of_longest_substring/README.md (1)

1-1: LGTM - Nice formatting improvement!

Converting the plain text title to a proper Markdown header improves document structure and readability.

pystrings/longest_self_contained_substring/README.md (1)

1-112: Excellent documentation!

The README provides comprehensive coverage of the problem definition, solution approach with detailed algorithm steps, and complexity analysis. The use of images for examples and solution walkthrough enhances understanding.

pystrings/longest_self_contained_substring/__init__.py (1)

1-97: Clarify the purpose of having two implementations.

This module exports two functions that solve the same problem but with vastly different time complexities:

  • longest_self_contained_substring: O(n³) brute-force approach
  • max_substring_length: O(n) optimized approach (matches the algorithm described in the README)

Questions to consider:

  1. Is the brute-force implementation needed? If it's for educational purposes or as a reference implementation, this should be documented in the module docstring or function docstrings.
  2. Which function should users prefer? The README only describes the O(n) algorithm, suggesting max_substring_length is the intended solution.
  3. Should both be public? Consider whether one should be private (prefixed with _) or if one should be removed entirely.

Would you like me to help generate a module-level docstring that clarifies when to use each function, or should one implementation be removed?

BrianLusina and others added 2 commits November 16, 2025 08:45
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@BrianLusina BrianLusina merged commit a92accd into main Nov 16, 2025
6 of 8 checks passed
@BrianLusina BrianLusina deleted the feat/longest-self-contained-substring branch November 16, 2025 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants